/**
 * Dashboard page tests
 */

import React from 'react';
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from 'react-query';
import Dashboard from '../../src/pages/Dashboard';

// Mock API services
jest.mock('../../src/services/api', () => ({
  telemetryApi: {
    getTelemetryStats: jest.fn(),
    getTelemetryPoints: jest.fn(),
  },
  authApi: {
    getCurrentUser: jest.fn(),
  },
}));

// Import mocked APIs for use in tests
const { authApi, telemetryApi } = require('../../src/services/api');

// Mock Antd components
jest.mock('antd', () => ({
  Row: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
  Col: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
  Card: ({ children, title, extra }: { children: React.ReactNode; title?: string; extra?: React.ReactNode }) => (
    <div>
      <h2>{title}</h2>
      {extra}
      <div>{children}</div>
    </div>
  ),
  Statistic: ({ title, value, suffix }: { title: string; value: number; suffix?: string }) => (
    <div>
      <div>{title}</div>
      <div>{value}{suffix}</div>
    </div>
  ),
  Progress: ({ percent }: { percent: number }) => <div>Progress: {percent}%</div>,
  Table: ({ columns, dataSource }: any) => (
    <table>
      <thead>
        <tr>
          {columns.map((col: any) => (
            <th key={col.key}>{col.title}</th>
          ))}
        </tr>
      </thead>
      <tbody>
        {dataSource.map((row: any, index: number) => (
          <tr key={index}>
            {columns.map((col: any) => (
              <td key={col.key}>{col.render ? col.render(row[col.dataIndex], row) : row[col.dataIndex]}</td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  ),
  Tag: ({ children, color }: { children: React.ReactNode; color?: string }) => (
    <span style={{ backgroundColor: color }}>{children}</span>
  ),
  Spin: ({ children }: { children: React.ReactNode }) => <div>Loading... {children}</div>,
  Alert: ({ message, type }: { message: string; type: string }) => (
    <div className={`alert-${type}`}>{message}</div>
  ),
  Typography: {
    Text: ({ children }: { children: React.ReactNode }) => <span>{children}</span>,
    Title: ({ children }: { children: React.ReactNode }) => <h2>{children}</h2>,
    Paragraph: ({ children }: { children: React.ReactNode }) => <p>{children}</p>,
  },
  Select: {
    Option: ({ children, value }: { children: React.ReactNode; value: string }) => <option value={value}>{children}</option>,
  },
  Button: ({ children, onClick, type, loading }: { children: React.ReactNode; onClick?: () => void; type?: string; loading?: boolean }) => (
    <button onClick={onClick} disabled={loading}>
      {loading ? 'Loading...' : children}
    </button>
  ),
  Empty: ({ description, image }: { description?: string; image?: any }) => (
    <div className="empty">
      {image && <div className="empty-image">Empty Image</div>}
      <div>{description || 'No data'}</div>
    </div>
  ),
  Space: ({ children }: { children: React.ReactNode }) => <div className="space">{children}</div>,
  Divider: () => <hr />,
  List: ({ children, dataSource, renderItem }: any) => (
    <div className="list">
      {dataSource?.map((item: any, index: number) => (
        <div key={index}>{renderItem ? renderItem(item) : item}</div>
      ))}
    </div>
  ),
  Badge: ({ children, count }: { children: React.ReactNode; count?: number }) => (
    <span className="badge">
      {children}
      {count && <span className="badge-count">{count}</span>}
    </span>
  ),
  PRESENTED_IMAGE_SIMPLE: 'empty-image',
}));

// Mock Recharts
jest.mock('recharts', () => ({
  BarChart: ({ children }: { children: React.ReactNode }) => <div>BarChart{children}</div>,
  Bar: () => <div>Bar</div>,
  XAxis: () => <div>XAxis</div>,
  YAxis: () => <div>YAxis</div>,
  CartesianGrid: () => <div>CartesianGrid</div>,
  Tooltip: () => <div>Tooltip</div>,
  Legend: () => <div>Legend</div>,
  PieChart: ({ children }: { children: React.ReactNode }) => <div>PieChart{children}</div>,
  Pie: () => <div>Pie</div>,
  Cell: () => <div>Cell</div>,
}));

const createTestQueryClient = () => new QueryClient({
  defaultOptions: {
    queries: { retry: false },
    mutations: { retry: false },
  },
});

describe('Dashboard Page', () => {
  let queryClient: QueryClient;

  beforeEach(() => {
    queryClient = createTestQueryClient();
    jest.clearAllMocks();

    // Mock successful auth
    authApi.getCurrentUser.mockResolvedValue({
      success: true,
      user: {
        user_id: 'test-user-123',
        email: 'test@example.com',
        name: 'Test User'
      }
    });
  });

  const renderDashboard = () => {
    return render(
      <QueryClientProvider client={queryClient}>
        <Dashboard />
      </QueryClientProvider>
    );
  };

  it('renders dashboard page title', () => {
    renderDashboard();
    expect(screen.getByText(/仪表板|Dashboard/i)).toBeInTheDocument();
  });

  it('displays loading state initially', () => {
    renderDashboard();
    expect(screen.getByText('Loading...')).toBeInTheDocument();
  });

  it('displays telemetry statistics after successful data fetch', async () => {
    const { telemetryApi } = require('../../services/api');
    telemetryApi.getTelemetryStats.mockResolvedValue({
      success: true,
      data: {
        total_metrics: 150,
        by_type: {
          histogram: 75,
          enum: 45,
          ukm_event: 20,
          ukm_metric: 10
        },
        top_components: {
          'Component1': 30,
          'Component2': 25,
          'Component3': 20
        },
        by_analysis_status: {
          analyzed: 60,
          not_analyzed: 50,
          needs_collection: 25,
          not_needed: 15
        },
        unassigned: 40
      }
    });

    renderDashboard();

    await waitFor(() => {
      expect(screen.getByText('150')).toBeInTheDocument(); // total metrics
    });
  });

  it('displays error message when API call fails', async () => {
    const { telemetryApi } = require('../../services/api');
    telemetryApi.getTelemetryStats.mockRejectedValue(new Error('API Error'));

    renderDashboard();

    await waitFor(() => {
      expect(screen.getByText(/Failed to load dashboard data/i)).toBeInTheDocument();
    });
  });

  it('displays analysis progress chart', async () => {
    const { telemetryApi } = require('../../services/api');
    telemetryApi.getTelemetryStats.mockResolvedValue({
      success: true,
      data: {
        total_metrics: 100,
        by_type: { histogram: 50, enum: 50 },
        top_components: {},
        by_analysis_status: {
          analyzed: 60,
          not_analyzed: 40,
          needs_collection: 0,
          not_needed: 0
        },
        unassigned: 0
      }
    });

    renderDashboard();

    await waitFor(() => {
      expect(screen.getByText('Progress: 60%')).toBeInTheDocument(); // analysis progress
    });
  });

  it('displays recent telemetry points table', async () => {
    const { telemetryApi } = require('../../services/api');
    telemetryApi.getTelemetryStats.mockResolvedValue({
      success: true,
      data: {
        total_metrics: 10,
        by_type: { histogram: 5, enum: 5 },
        top_components: {},
        by_analysis_status: {
          analyzed: 5,
          not_analyzed: 5,
          needs_collection: 0,
          not_needed: 0
        },
        unassigned: 0
      }
    });

    telemetryApi.getTelemetryPoints.mockResolvedValue({
      success: true,
      data: [
        {
          id: 1,
          name: 'TestMetric1',
          type: 'histogram',
          component: 'TestComponent',
          analysis_status: 'ANALYZED',
          file_path: '/test/path1.xml'
        },
        {
          id: 2,
          name: 'TestMetric2',
          type: 'enum',
          component: 'TestComponent',
          analysis_status: 'NOT_ANALYZED',
          file_path: '/test/path2.xml'
        }
      ],
      total: 2,
      page: 1,
      page_size: 10
    });

    renderDashboard();

    await waitFor(() => {
      expect(screen.getByText('TestMetric1')).toBeInTheDocument();
      expect(screen.getByText('TestMetric2')).toBeInTheDocument();
    });
  });

  it('displays metrics by type distribution', async () => {
    const { telemetryApi } = require('../../services/api');
    telemetryApi.getTelemetryStats.mockResolvedValue({
      success: true,
      data: {
        total_metrics: 100,
        by_type: {
          histogram: 50,
          enum: 30,
          ukm_event: 15,
          ukm_metric: 5
        },
        top_components: {},
        by_analysis_status: {
          analyzed: 50,
          not_analyzed: 50,
          needs_collection: 0,
          not_needed: 0
        },
        unassigned: 0
      }
    });

    renderDashboard();

    await waitFor(() => {
      expect(screen.getByText('50')).toBeInTheDocument(); // histogram count
    });
  });

  it('handles refresh functionality', async () => {
    const { telemetryApi } = require('../../services/api');
    telemetryApi.getTelemetryStats.mockResolvedValue({
      success: true,
      data: {
        total_metrics: 100,
        by_type: { histogram: 50, enum: 50 },
        top_components: {},
        by_analysis_status: {
          analyzed: 50,
          not_analyzed: 50,
          needs_collection: 0,
          not_needed: 0
        },
        unassigned: 0
      }
    });

    renderDashboard();

    await waitFor(() => {
      expect(telemetryApi.getTelemetryStats).toHaveBeenCalledTimes(1);
    });

    // Find and click refresh button if it exists
    const refreshButton = screen.getByText('Refresh');
    if (refreshButton) {
      fireEvent.click(refreshButton);

      await waitFor(() => {
        expect(telemetryApi.getTelemetryStats).toHaveBeenCalledTimes(2);
      });
    }
  });

  it('displays zero state when no metrics available', async () => {
    const { telemetryApi } = require('../../services/api');
    telemetryApi.getTelemetryStats.mockResolvedValue({
      success: true,
      data: {
        total_metrics: 0,
        by_type: {},
        top_components: {},
        by_analysis_status: {
          analyzed: 0,
          not_analyzed: 0,
          needs_collection: 0,
          not_needed: 0
        },
        unassigned: 0
      }
    });

    renderDashboard();

    await waitFor(() => {
      expect(screen.getByText('0')).toBeInTheDocument();
    });
  });

  it('formats large numbers correctly', async () => {
    const { telemetryApi } = require('../../services/api');
    telemetryApi.getTelemetryStats.mockResolvedValue({
      success: true,
      data: {
        total_metrics: 1500000,
        by_type: { histogram: 750000, enum: 750000 },
        top_components: {},
        by_analysis_status: {
          analyzed: 750000,
          not_analyzed: 750000,
          needs_collection: 0,
          not_needed: 0
        },
        unassigned: 0
      }
    });

    renderDashboard();

    await waitFor(() => {
      // Should format large numbers (implementation dependent)
      expect(screen.getByText(/1500000|1.5M|1,500,000/)).toBeInTheDocument();
    });
  });

  it('is accessible with proper ARIA labels', async () => {
    const { telemetryApi } = require('../../services/api');
    telemetryApi.getTelemetryStats.mockResolvedValue({
      success: true,
      data: {
        total_metrics: 100,
        by_type: { histogram: 50, enum: 50 },
        top_components: {},
        by_analysis_status: {
          analyzed: 50,
          not_analyzed: 50,
          needs_collection: 0,
          not_needed: 0
        },
        unassigned: 0
      }
    });

    renderDashboard();

    await waitFor(() => {
      // Check for proper ARIA labels on charts and tables
      const charts = document.querySelectorAll('[role="img"], [aria-label]');
      expect(charts.length).toBeGreaterThan(0);
    });
  });

  it('handles network errors gracefully', async () => {
    const { telemetryApi } = require('../../services/api');
    telemetryApi.getTelemetryStats.mockRejectedValue(new Error('Network Error'));

    renderDashboard();

    await waitFor(() => {
      expect(screen.getByText(/Network Error|Failed to load/i)).toBeInTheDocument();
    });
  });
});